package com.spsoft.dmzeinvoice.common.aspect;

import com.alibaba.fastjson.JSONObject;
import com.spsoft.core.constants.CommonConstants;
import com.spsoft.core.enums.ResponseEnum;
import com.spsoft.core.model.Result;
import com.spsoft.dmzeinvoice.common.annotation.DmzLog;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * 切面类，含有多个通知
 */
@Component
@Aspect
@Slf4j
@RequiredArgsConstructor
public class DmzLogAspect {
//    private final VmsDmzLogService vmsDmzLogService;

    ThreadLocal<Long> currentTime = new ThreadLocal<>();

    // 声明公共切入点
    @Pointcut("@annotation(com.spsoft.dmzeinvoice.common.annotation.DmzLog)")
    private void myPointCut() {
    }

    // 切入点当前有效
    @Before("myPointCut()")
    public void myBefore(JoinPoint joinPoint) {
        // 2方法执行前调用 日志打印顺序-3
    }

    @AfterReturning(value = "myPointCut()", returning = "result")
    public void myAfterReturning(JoinPoint joinPoint, Object result) {
        // 3方法执行return前调用 日志打印顺序-4-出现异常不打印
    }

    @After("myPointCut()")
    public void myAfter(JoinPoint joinPoint) {
        // 4方法执行后调用 日志打印顺序-5
    }

    @Around(value = "myPointCut()")
    public Object myAround(ProceedingJoinPoint joinPoint) {
        try {
            currentTime.set(System.currentTimeMillis());
            Object obj = joinPoint.proceed();
            long requestTime=System.currentTimeMillis() - currentTime.get();
            currentTime.remove();

            printSaveLog(joinPoint, obj, requestTime);
            return obj;

        } catch (Throwable e) {
            log.error("RequestMappingLog 打印日志异常");
            // TODO 需要增加报警机制
//            throw new DmzLogException();
        }
        return null;
    }

    @AfterThrowing(value = "myPointCut()", throwing = "e")
    public void myAfterThrowing(JoinPoint joinPoint, Throwable e) throws Throwable {
        String method = joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName();
        printSaveLog(joinPoint, null, -1L);
        log.error("调用方法【{}】出现异常：", method, e);// 日志打印顺序-出现异常时打印
    }

    private String getRequestParamStr(JoinPoint joinPoint) {
        CopyOnWriteArrayList<Object> args = new CopyOnWriteArrayList<>(Arrays.asList(joinPoint.getArgs()));
        args.removeIf(arg -> arg instanceof HttpServletRequest || arg instanceof HttpServletResponse || arg instanceof MultipartFile);
        return JSONObject.toJSONString(args.get(0));
    }

    private void printSaveLog(JoinPoint joinPoint, Object obj, long timeConsume) {
        String method = joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName();

        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        // 记录下请求内容
        String ip = request.getRemoteAddr();
        String url = request.getRequestURL().toString();

        // 获取注解的参数
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        DmzLog annotation = signature.getMethod().getAnnotation(DmzLog.class);
        // 获取入参
        String paramStr = getRequestParamStr(joinPoint);
        String responseStr = "";
        if (Objects.nonNull(obj)) {
            responseStr = JSONObject.toJSONString(obj);
        }
        log.info("调用方法【{}】，方法说明：{}， 请求URL：{}, 请求IP：{}，入参:{}， 出参:{}, 耗时：{} 毫秒",
                method,
                annotation.leqiName(),
                url,
                ip,
                paramStr,
                responseStr,
                timeConsume
        );
//
//        VmsDmzLog dmzLog = new VmsDmzLog();
//        try {
//            BaseNsrRequestParams params = JSONObject.parseObject(paramStr, BaseNsrRequestParams.class);
//
//            // 请求结果入库
//            dmzLog.setCreatedBy(params.getCreateUser());
//            dmzLog.setCreatedTime(new Date());
//            dmzLog.setNsrsbh(params.getNsrsbh());
//            dmzLog.setDeptCode(params.getDeptCode());
//            dmzLog.setInterfaceName(annotation.leqiName());
//            dmzLog.setRequestJson(paramStr);
//            dmzLog.setResponseJson(responseStr);
//            dmzLog.setResponseCode(getResponseCode(responseStr));
//            vmsDmzLogService.save(dmzLog);
//        } catch (RuntimeException e) {
//            //
//            log.error("保存乐企请求日志异常，dmzLog={}，", dmzLog, e);
////            throw new DmzLogException();
//        }
    }

    private String getResponseCode(String responseStr) {
        if (StringUtils.isBlank(responseStr)) {
            return ResponseEnum.BUSINESS_ERROR.getCode();
        }

        Result result = JSONObject.parseObject(responseStr, Result.class);
        if (result.getCode().equals(CommonConstants.REST_SUCCESS)) {
            return "00";
        }
        return result.getCode();
    }
}


